package com.jamie.jvm.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * ABA问题的解决 AtomicStampedReference
 * @author jamie
 * @date 2021/3/6 21:07
 */
public class ABADemo {

    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);

    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);

    public static void main(String[] args) {
        //        abaCreate();
        abaSolve();

    }

    /**
     * 模拟aba问题产生
     */
    public static void abaCreate() {
        System.out.println("===========以下是ABA问题的产生==============");
        // 模拟ABA操作
        new Thread(() -> {
            atomicReference.compareAndSet(100, 101);
            atomicReference.compareAndSet(101, 100);
        }, "t1").start();

        new Thread(() -> {
            // 暂停1秒钟t2线程，保证上面的t1线程完成了一次ABA操作
            threadSleep(1);
            System.out.println(atomicReference.compareAndSet(100, 2019) + "\t " + atomicReference.get());
        }, "t2").start();
    }

    /**
     * 模拟aba问题解决
     */
    private static void abaSolve() {
        System.out.println("===========以下是ABA问题的解决==============");
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t第一次版本号：" + atomicStampedReference.getStamp());
            // 暂停1秒钟t3线程,保证t4线程可以拿到通用的版本号
            threadSleep(1);
            atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(),
                    atomicStampedReference.getStamp()
                    + 1);
            System.out.println(Thread.currentThread().getName() + "\t第二次版本号：" + atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(),
                    atomicStampedReference.getStamp()
                    + 1);
            System.out.println(Thread.currentThread().getName() + "\t第三次版本号：" + atomicStampedReference.getStamp());
        }, "t3").start();

        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "\t第一次版本号：" + stamp);
            // 暂停3秒钟t4线程，保证上面的t3线程完成了一次ABA操作
            threadSleep(3);
            boolean result = atomicStampedReference.compareAndSet(100, 2019, stamp, stamp + 1);
            int stamp1 = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "\t修改成功否：" + result + "\t 当前最新版本号为：" + stamp1);
            System.out.println(Thread.currentThread().getName()
                    + "\t当前实际最新值为："
                    + atomicStampedReference.getReference());
        }, "t4").start();
    }

    /**
     * 线程休眠
     * @param seconds 单位秒
     */
    private static void threadSleep(int seconds) {
        try{
            TimeUnit.SECONDS.sleep(seconds);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }

}
